在linux中 应用程序如何调用模块内的函数

在bbs上发了个如题所示的大土帖,结果没一个回复,哎,真丢人~~~,蒙师兄指点,才初步搞清楚linux模块函数的调用机制:


首先,应用程序是无法直接访问模块中的函数的(即使是你自编自挂的模块--实际上它也是内核模块),用户空间与内核空间之间只有通过一些特定的系统函数来进行通讯(如什么user_to_kernel),而绝对不可能通过“直接调用模块里的函数”这种形式来通讯。


那么,所编写的模块里的函数怎么才能被执行?由谁调用?其实答案很简单,它们是由内核来调用的,注意,是由内核来调用的。比如 init_module() 和  cleanup_module() 函数,分别是在挂载模块(insmod)和卸载模块(rmmod)的时候,内核根据命令参数来调用此两个函数的,它们分别负责模块的初始化及后处理。


很自然的,下一个疑问接踵而至,--模块里的其他函数如何被调用?比如我写的模块中除了 init_module() 和  cleanup_module() 函数外,还写了一个 hello_world() 函数,简单的输出“hello world”到控制台,好,接下来就是这次分析的关键,前面我们强调了模块中的函数是由内核来调用的,除此之外没有别的机会使它被执行到。那如果我们的 hello_world() 函数不能被内核调用,这不就意味着它永远也不可能被执行到吗?确实是这样,换句话说,在这种情况下它就是一段垃圾代码,永无见天日之时。怎么样才能使我们的 hello_world() 函数被执行?显然,关键在于让内核认识它,即内核能找到它。那么,怎样才能使内核找到这个函数?再进一步的问题是,内核为什么要去找这个函数?


第一问的答案是,内核通过系统中特定的数据结构来找到函数的,当然,这意味着在你的模块程序中,仅仅写上 hello_world() 函数的代码是不够的,还应该再做几步工作:

a,首先,系统中的各类数据结构那么多,要使用哪个呢?这由你这个模块的注册性质决定,譬如你的模块是一个USB设备驱动模块,那么你就需要填写usb设备驱动程序的数据结构(通常数据结构都是结构体(struct)的形式)
struct usb_driver{第一项;第二项;第三项;.......}
这里的各项有些是字符串,有些是函数指针,具体请查资料。

b,把 hello_world() 的函数指针放进一个数据结构中。我们还是接着举usb设备驱动程序模块的例子吧,在它的数据结构usb_driver{}中,选一个恰好是函数指针的项,把 hello_world() 函数的指针放进去(通过函数名),再填满这个数据结构的其他部分(不想填的话就空着吧:P,用分号分隔即可)。

c,填完之后,回到第一问中,怎样使内核能够找到这个 hello_world() 函数?回头想想,当我们填完了数据结构,也就决定了我们所编的模块的性质,在此例中它是作为一个usb设备驱动模块,但是要让内核知道它的性质,还得通过执行usb设备驱动程序的系统注册函数 usb_register(struct usb_struct *drv),向内核注册这个模块以及这个填好的数据结构。注意到了吧,注册函数的参数就是我们前面所填写的usb设备驱动模块的数据结构,也就是说,执行了这个注册函数之后,内核里就认识了这个模块,并且得到了 hello_world() 函数的指针!哈哈,这就为我们的 hello_world() 函数找到了生存的意义--它有可能被执行了!(偶觉得,程序生存的意义就在于被执行,就跟偶们生存的意义在于编程序一样:P)

d,还得补充一下,usb_register(struct usb_struct *drv) 函数必须被放在 init_module() 中,因为在注册这个决定模块性质的数据结构之前(短语太长,可约为“这个数据结构”),模块中可以被直接执行到的函数只有 init_module() 和 cleanup_module() 两个,如果不把握这个机会赶紧注册数据结构的话,那我们的 hello_world() 函数又要永不见天日了:(。


现在来看第二问,内核为什么要去找这个函数?还是用usb设备驱动模块来解释,其他类型的模块偶不了解,还请大虾们补充。对于usb设备驱动模块,内核找这个函数的原因当然是,用户程序对usb设备进行了某种操作,而这种操作需要usb设备驱动程序的函数来进行实现。我们前面的工作中已将这个usb设备驱动模块的数据结构注册进内核数据结构链表,内核根据我们这个模块对应的数据结构usb_driver的各项定义,找到对应用户要求的那个操作的那个函数。假设我们把 hello_world() 函数的指针放在usb_driver的 write() 选项中,那么当用户对usb设备进行写操作的时候,就调用了 hello_world() 函数,控制台屏幕上会打出“hello world ”,其他什么操作都没有,哈哈,一定很有趣。(这里我们假设此usb设备的驱动程序正好是我们编的那个)

自己的一点心得,大部分是凭空想像的,错误之处一定数不胜数,还请各位大虾费心批评指教!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 嵌入式Linux应用程序开发框架模块化代码实现有助于提高应用程序的可维护性和可扩展性。模块化代码实现是将应用程序划分为若干个模块,每个模块负责完成不同的功能,而模块之间通过接口进行交互。 模块化代码实现能够提升开发效率,在代码维护和修复时更加便捷。此外,随着应用程序需求的不断增加,模块化代码实现还可以降低开发难度和风险。 在嵌入式Linux应用程序开发框架,实现模块化代码需要遵守一定的规则和流程。首先,需要将整个应用程序划分为若干个模块,并确定模块之间的接口。其次,在模块内部要尽可能地减少全局变量的使用,并将变量和函数的作用域限定在模块内。最后,在运行时,需要保留各个模块之间的数据完整性和通信效率。 模块化代码实现可以采用多种技术,如面向对象设计模式、单例模式、观察者模式和工厂模式等。还可以利用现有的框架和库来实现模块化代码,如Qt和Boost等。 总之,模块化代码实现是嵌入式Linux应用程序开发的重要技术,能够提高应用程序的可维护性和可扩展性,降低开发难度和风险。开发人员需要在设计应用程序时,注重代码的模块化和接口设计,遵循规范和流程实现模块化代码。 ### 回答2: 嵌入式Linux 应用程序开发框架的模块化代码实现是一种重要的编程方法,它可以提高软件的可维护性、可扩展性和可重用性。模块化代码实现的核心思想是将软件分解成独立的、可重用的模块,每个模块只关注自己的功能,与其它模块之间的接口明确,便于维护和扩展。下面介绍一下模块化代码实现的应用方法。 首先,需要把软件分解成多个模块。每个模块实现一个或多个相关的功能,且与其它模块之间的接口定义明确。模块之间的通信可以通过函数调用、全局变量等方式实现。每个模块都应该是独立的,它不依赖于其它模块的实现细节。这样,当需要修改某个模块时,只需要修改这个模块,不会对其它模块产生影响。 其次,每个模块需要定义对外接口。这些接口包括函数、功能参数和返回值等。对于涉及到硬件操作的模块,还需要定义相关的数据结构和硬件寄存器的抽象表示方法。在设计接口时,需要考虑到接口的灵活性和扩展性。如果在设计接口时考虑得不够周全,会导致后期扩展时出现难以预料的问题。 最后,需要采用合适的编程技术来实现模块化代码。常见的编程技术包括面向对象的编程、模块化编程和设计模式等。应该根据实际情况选择适合的编程技术。 总之,模块化代码实现是一种有效的编程方法,它可以提高软件的可维护性、可扩展性和可重用性。在嵌入式Linux应用程序开发,采用模块化代码实现方法可以有效地降低开发难度,提高开发效率。 ### 回答3: 嵌入式Linux应用程序开发框架是一种软件开发工具,它可以帮助开发人员快速构建嵌入式系统上的应用程序。其模块化代码实现是该框架的一个重要特点。 模块化代码实现是一种将代码划分为独立的、可重用的模块的编程方式。在嵌入式系统上,采用这种编程方式可以使代码更加清晰、易于维护,并且能够提供更大的灵活性和可扩展性。具体实现方式包括函数模块化、文件模块化,以及利用模块化框架等。 在嵌入式Linux应用程序开发框架模块化代码实现常用于驱动程序和应用程序的开发。驱动程序指的是用于控制嵌入式系统上的硬件设备的程序,而应用程序则是指嵌入式系统上的用户程序。这些程序的模块化代码实现可以使其更易于调试,也可以使开发人员更方便地进行代码的维护和扩展。 总之,嵌入式Linux应用程序开发框架之模块化代码实现是一种非常重要的编程方式,在嵌入式系统上具有广泛的应用。通过模块化代码实现,可以使代码更加清晰、易于维护,并且可以提高代码的可扩展性和灵活性,让开发人员更加方便地进行开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值